package cz.tomasdvorak.cars;

import cz.tomasdvorak.cars.auth.Auth;
import cz.tomasdvorak.cars.auth.MyAuthenticatedWebSession;
import cz.tomasdvorak.cars.dao.ExpensesDao;
import cz.tomasdvorak.cars.dao.UsersDao;
import cz.tomasdvorak.cars.dao.VehiclesDao;
import cz.tomasdvorak.cars.pages.BasePage;
import cz.tomasdvorak.cars.pages.MainPage;
import cz.tomasdvorak.cars.pages.signing.SignInPage;
import cz.tomasdvorak.cars.resources.ImageResource;
import cz.tomasdvorak.cars.utils.ClassExplorer;
import cz.tomasdvorak.cars.wicket.components.auth.MetadataAuthorizationStrategy;
import cz.tomasdvorak.cars.wicket.components.converters.SimpleDateConverter;
import org.apache.log4j.Logger;
import org.apache.wicket.IConverterLocator;
import org.apache.wicket.Page;
import org.apache.wicket.authentication.AuthenticatedWebApplication;
import org.apache.wicket.authentication.AuthenticatedWebSession;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.util.convert.ConverterLocator;

import java.util.Date;

public class CarExpensesApp extends AuthenticatedWebApplication {

    private static final Logger log = Logger.getLogger(CarExpensesApp.class);

    private static final String WEBPAGES_ROOT_PACKAGE = "cz.tomasdvorak.cars.pages";

    private UsersDao usersDao;
    private VehiclesDao vehiclesDao;
    private ExpensesDao expensesDao;

    public void setUsersDao(UsersDao usersDao) {
        this.usersDao = usersDao;
    }

    public UsersDao getUsersDao() {
        return usersDao;
    }

    public VehiclesDao getVehiclesDao() {
        return vehiclesDao;
    }

    public void setVehiclesDao(VehiclesDao vehiclesDao) {
        this.vehiclesDao = vehiclesDao;
    }

    public ExpensesDao getExpensesDao() {
        return expensesDao;
    }

    public void setExpensesDao(ExpensesDao expensesDao) {
        this.expensesDao = expensesDao;
    }

    public Class<? extends Page> getHomePage() {
        return MainPage.class;
    }

    protected Class<? extends AuthenticatedWebSession> getWebSessionClass() {
        return MyAuthenticatedWebSession.class;
    }

    protected Class<? extends WebPage> getSignInPageClass() {
        return SignInPage.class;
    }

    @Override
    protected void init() {
        super.init();
        getSecuritySettings().setAuthorizationStrategy(new MetadataAuthorizationStrategy(new Auth()));
        // remove wicket markup from output
        getMarkupSettings().setStripWicketTags(true);
        getSharedResources().add("imageResource", new ImageResource());
        makeNiceUrls();
    }

    /**
     * Mount all pages as nice urls. Path is based on class name, slightly modified.
     */
    private void makeNiceUrls() {
        try {
            Class[] classes = ClassExplorer.getClasses(WEBPAGES_ROOT_PACKAGE);
            for(Class clazz : classes) {
                if(BasePage.class.isAssignableFrom(clazz)) {
                    mountUrl(clazz);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void mountUrl(Class<? extends BasePage> clazz) {
        String path = getResourceUrl(clazz);
        log.info("Mounted url: " + path);
        mountBookmarkablePage(path, clazz);
    }

    /**
     * Make url from class name, remove "Page" from name, uppercase letters prefix with -, then all to lower case
     */
    private String getResourceUrl(Class<? extends BasePage> clazz) {
        // TODO: localized nice urls
        StringBuilder path = new StringBuilder();
        String name = clazz.getSimpleName().replace("Page", "");
        for (int i = 0; i < name.length(); i++) {
            String suffix = "";
            if (i + 1 < name.length()) {
                String nextChar = name.substring(i + 1, i + 2);
                if (nextChar.equals(nextChar.toUpperCase())) {
                    suffix = "-";
                }
            }
            path.append(name.substring(i, i + 1).toLowerCase()).append(suffix);
        }
        return path.toString();
    }

    @Override
    protected IConverterLocator newConverterLocator() {
        ConverterLocator converterLocator = new ConverterLocator();
        converterLocator.set(Date.class, new SimpleDateConverter());
        return converterLocator;
    }
}
